"""
Funny example on why using couroutines
"""

import thread

class TaskHandler(object):
    """Runs this cooperative thread inside a
    main loop."""
    
    def __init__(self, gen, idle_add):
        self.gen = gen
        self.idle_add=idle_add
        
    def wait_for_task(self, func, args=(), kwargs={}):
        """Creates a thread to run the extensive task"""
        def my_thread():
            data = func(*args, **kwargs)
            self.idle_add(self.in_gloop, data)

        thread.start_new_thread(my_thread, ())

    def in_gloop(self,  *args):
        try:
            if len(args) > 0:
                self.gen.send(*args)
            extensive_task = self.gen.next()
            self.wait_for_task(*extensive_task)
            return True
        except StopIteration:
            return False

    def __call__(self, data=None):
        return self.in_gloop()

def call(func, *args, **kwargs):
    """Makes it easier to yield function calls."""
    return lambda: func(*args, **kwargs)




thread_pool = []
running = True

def main():
    global running
    running = True
    while running:
        for arg in thread_pool:
            (thread, data) = arg
            if thread(data):
                thread_pool.remove(arg)

def idle_add(func, data=None):
    thread_pool.append((func, data))

def main_quit():
    global running
    running = False

def long_task(how_long):
    import time
    time.sleep(how_long)
    return how_long

def unblocking_call():
    print "waiting for input..."
    print "We've waited for %r seconds!" % (yield call(long_task, 3))
    print (yield)
    main_quit()
    print "done"

if __name__ == '__main__':
    idle_add(TaskHandler(unblocking_call()))
    main()
    
